package com.tobeface.wechat.core.timestamp;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.tobeface.modules.lang.Langs;
import com.tobeface.modules.lang.Requires;

import java.util.concurrent.TimeUnit;

/**
 * @author loudyn
 */
public final class DefaultWeChatTimestampService extends AbstractTimestampService {

    private static final long DEFAULT_TIMESTAMP_LIFECYCLE = TimeUnit.MINUTES.toMillis(5);
    private final long timestampLifecycle;
    private final LoadingCache<String, Boolean> timestampRepository;

    /**
     *
     */
    public DefaultWeChatTimestampService() {
        this(DEFAULT_TIMESTAMP_LIFECYCLE);
    }

    /**
     * @param timestampLifecycle
     */
    public DefaultWeChatTimestampService(long timestampLifecycle) {
        this.timestampLifecycle = timestampLifecycle;

        long lifecyleMins = TimeUnit.MILLISECONDS.toMinutes(timestampLifecycle);
        CacheLoader<String, Boolean> alwaysFalse = new CacheLoader<String, Boolean>() {
            @Override
            public Boolean load(String key) throws Exception {
                return Boolean.FALSE;
            }
        };
        this.timestampRepository = CacheBuilder.newBuilder()
                                                .expireAfterWrite(timestampLifecycle, TimeUnit.MILLISECONDS)
                                                .maximumSize(lifecyleMins * 60 * 1000)
                                                .build(alwaysFalse);
    }

    @Override
    public final boolean isTimestampAcceptable(String timestamp) {
        try {

            long now = System.currentTimeMillis();
            long timestampMillis = TimeUnit.SECONDS.toMillis(Long.parseLong(timestamp));
            return Math.abs(now - timestampMillis) < timestampLifecycle;
        } catch (Exception e) {
            getLogger().warn("Unacceptable timestamp {}", timestamp);
            return false;
        }
    }

    @Override
    public boolean isTimestampNonceFound(String timestamp, String nonce) {
        Requires.hasText(timestamp);
        Requires.hasText(nonce);
        try {

            return timestampRepository.get(String.format("%s-%s", timestamp, nonce));
        } catch (Exception e) {
            throw Langs.impossiable();
        }
    }

    @Override
    public void tracingTimestamp(String timestamp, String nonce) {
        Requires.hasText(timestamp);
        Requires.hasText(nonce);
        timestampRepository.put(String.format("%s-%s", timestamp, nonce), Boolean.TRUE);
    }
}
